<template>
  <div class="container">
    <div class="app-container">
      <div class="operate">
        <el-button type="primary" size="mini" @click="addVisible = true">添加角色</el-button>
      </div>
      <!-- 放置table组件 -->
      <el-table :data="tableData" border style="width: 100%" size="medium" class="table">
          <el-table-column label="序号" width="50"></el-table-column>
          <el-table-column prop="name" label="角色" width="200">
            <template v-slot="{ row }">
              <el-input v-if="row.isEdit" v-model="row.editRow.name" size="mini"></el-input>
              <span v-else>{{row.name}}</span>
            </template>
          </el-table-column>
          <el-table-column prop="state" label="启用" width="200">
            <template v-slot="{ row }">
              <el-switch v-if="row.isEdit" v-model="row.editRow.state" :active-value="1" :inactive-value="0"></el-switch>
              <span v-else>{{row.state === 1 ? '已启用' : '未启用'}}</span>
            </template>
          </el-table-column>
          <el-table-column prop="description" label="描述">
            <template v-slot="{ row }">
              <el-input v-if="row.isEdit" v-model="row.editRow.description" type="textarea" size="mini" :rows="2"></el-input>
              <span v-else>{{row.description}}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作">
            <template v-slot="{ row }">
              <template v-if="row.isEdit">
                <el-button type="primary" size="mini" @click="tableRowConfirm(row)">确定</el-button>
                <el-button size="mini" @click="row.isEdit = false">取消</el-button>
              </template>
              <template v-else>
                <el-button type="text" size="medium" @click="btnPermission(row.id)">分配权限</el-button>
                <el-button type="text" size="medium" @click="btnEditRow(row)" style="margin-right: 10px;">编辑</el-button>
                <el-popconfirm title="这是一段内容确定删除吗？" @confirm="deleteConfirm(row.id)">
                  <el-button type="text" size="medium" slot="reference">删除</el-button>
                </el-popconfirm>
              </template>
            </template>
          </el-table-column>
      </el-table>
      <!-- 放置分页组件 -->
      <el-row type="flex" justify="center" style="height: 60px;" align="middle">
          <el-pagination
            layout="prev, pager, next"
            :current-page="pageParams.page"
            :page-size="pageParams.pagesize"
            :total="pageParams.total"
            @current-change="changePage">
          </el-pagination>
          <!-- 当前页改变时，即点击左右箭头/页码，会触发该内置自定义事件current-change -->
      </el-row>
    </div>
    <!-- 放置添加角色的弹层 -->
    <el-dialog title="新增角色" :visible.sync="addVisible" width="25%" @close="close">
      <el-form :model="addForm" ref="addForm" :rules="rules" label-width="100px">
        <el-form-item label="角色名称" prop="name">
          <el-input v-model="addForm.name" size="small" style="width: 300px;"></el-input>
        </el-form-item>
        <!-- 若是不需要绑定对应的校验规则，就不加prop，但是要重置表单数据为初始值时，需要加prop才生效 -->
        <el-form-item label="启用" prop="state">
          <el-switch v-model="addForm.state" :active-value="1" :inactive-value="0"></el-switch>
        </el-form-item>
        <el-form-item label="角色描述" prop="description">
          <el-input v-model="addForm.description" type="textarea" size="small" :rows="3" style="width: 300px;"></el-input>
        </el-form-item>
      </el-form>
      <div class="dialog-footer">
         <el-button @click="close" size="small">取 消</el-button>
         <el-button type="primary" @click="confirm" size="small">确 定</el-button>
       </div>
    </el-dialog>
    <!-- 放置分配权限的弹层 -->
    <el-dialog title="分配权限" :visible.sync="permissionVisible" width="40%">
      <!-- default-checked-keys	默认勾选的节点的 key 的数组 -->
      <!-- check-strictly	在显示复选框的情况下，是否严格的遵循父子不互相关联的做法，默认为 false -->
      <el-tree
        :data="treeData" 
        :props="{label: 'name', children: 'children'}"
        node-key="id"
        :default-checked-keys="permIds"
        ref="tree"
        check-strictly
        show-checkbox
        default-expand-all>
      </el-tree>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" size="small" @click="permissionConfirm">确 定</el-button>
        <el-button size="small" @click="permissionVisible = false">取 消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
  import { getRoleList, addRole, updateRole, deleteRole, getRoleDetail, assignPermission } from '@/api/role'
  import { getPermissionList } from '@/api/permission'
  import { transListToTreeData } from '@/utils'
export default {
  name: 'Role',
  data() {
    return {
      // 点击分配权限按钮时的当前行角色id
      currentRoleId: null,
      // 当前角色已有的权限id的数组
      permIds: [],
      // 树形权限点展示的数据
      treeData: [],
      // 分配权限弹层可见性
      permissionVisible: false,
      // 添加弹层可见性
      addVisible: false,
      // 添加弹层的表单数据
      addForm: {
        name: '',
        state: 0,
        description: ''
      },
      // 添加弹层的表单数据校验规则
      rules:{
        name: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
        description: [{ required: true, message: '角色描述不能为空', trigger: 'blur' }]
      },
      // 分页信息
      pageParams: {
        page: 1,  // 当前页码数
        pagesize: 5,  // 当前页需要的数据条数
        total: 0
      },
      // 表格数据
      tableData:  [{
          id: '1',
          name: '系统管理员',
          state: 0,
          description: '管理整合平台，可以操作企业所有功能'
        }]
    }
  },
  methods: {
    async getRoleList() {
      // 调用分页查询的请求接口
     const {rows, total} = await getRoleList(this.pageParams)
     // 给收到的数据即一个数组对象，给数组里面的每个对象都添加一个是否编辑的标记属性，用于点击编辑后修改为编辑状态进行表格行的条件渲染
     // 其次，数组中的每个对象还要添加一个属性，该属性对象里存着的是编辑状态下的数据，初始值是从服务器里传过来的每项值
     rows.forEach(item => {
       item.isEdit = false
       item.editRow = {
         name: item.name,
         state: item.state,
         description: item.description
       }
     })
     // 修改表格数据，根据新数据重新渲染表格
     this.tableData = rows
     // 修改所有页加起来的总条目数
     this.pageParams.total = total
    },
    // 分页组件点击不同页码触发的方法
    changePage(newPage) {
      this.pageParams.page = newPage
      this.getRoleList()
    },
    // 添加角色弹层的关闭功能
    close() {
      this.$refs.addForm.resetFields()
      this.addVisible = false
    },
    // 添加角色弹层的确认按钮功能
    confirm() {
      this.$refs.addForm.validate(async (valid) => {
        if(valid) {
          // 调用新增角色请求接口
          await addRole(this.addForm)
          // 重新渲染当前页，改变总数目条数
          this.getRoleList()
          // 弹出成功消息
          this.$message.success('新增角色成功')
          // 重置表单，关闭弹层
          this.close()
        }
      })
    },
    // 表格行中点击编辑的功能
    btnEditRow(row) {
      // 修改编辑行中的数据为请求传递过来的初始数据
      row.editRow.name = row.name
      row.editRow.state = row.state
      row.editRow.description = row.description
      // 修改为编辑状态
      row.isEdit = true
    },
    // 表格行编辑状态下，点击确定按钮的功能
    async tableRowConfirm(row) {
      if (row.editRow.name.trim() && row.editRow.description.trim()) {
        // 调用修改角色的请求接口，去请求修改服务器中真正的数据
        await updateRole({...row.editRow, id: row.id})
        // 弹出修改成功消息
        this.$message({type: 'success', message: '修改角色成功'})
        // 更新页面显示为编辑行里修改后的数据，这里不能直接调用请求接口重新获取数据渲染页面，要不然其他行点开了编辑，会修改为退出编辑状态
        // 这样的做法支持多行同时编辑，其他行不受影响
        // row.name = row.editRow.name
        // row.state = row.editRow.state
        // row.description = row.editRow.description
        // 下面是简化写法，第二个参数中源对象的属性会把row中同名的属性覆盖，同时editRow属性不受影响
        Object.assign(row, {
          ...row.editRow,
          isEdit: false  // 退出编辑状态
        })
      } else {
        this.$message.warning('角色名称和描述不能为空')
      }
    },
    // 点击表格行中删除操作里出现的气泡确认框中确定按钮会触发的事键回调，功能如下
    async deleteConfirm(id) {
      // 调用删除角色的请求接口
      await deleteRole(id)
      // 弹出删除成功消息
      this.$message.success('删除角色成功')
      // 判断删除的该条数据是否是该页面的最后一个数据
      if (this.tableData.length === 1) {
        // 是的话获取上一页的所有数据，重新渲染页面
        this.pageParams.page = this.pageParams.page - 1
        this.getRoleList()
      } else {
        // 直接获取当前页的数据列表，更新表格数据，渲染页面
        this.getRoleList()
      }
    },
    // 点击分配权限的功能
    async btnPermission(id) {
      // 存储点击对应行的角色id
      this.currentRoleId = id
      
      // 【注意】必须先获取已有权限id，赋值修改data里的数据后，再去获取所有的权限点列表，这样赋值后，重新解析模板默认选中的权限id一定是最新的
      
      // 调用获取角色详情的请求接口，角色详情数据中含有角色关联的权限点数组
      const { permIds } = await getRoleDetail(id)
      // 赋值当前角色已有的权限id的数组
      this.permIds = permIds
      
      // 调用获取权限点列表的请求接口
      const result = await getPermissionList()
      this.treeData = transListToTreeData(result, 0)
      
      // 弹出权限弹层
      this.permissionVisible = true
    },
    // 点击分配权限弹层中确定按钮的功能
    async permissionConfirm() {
      // 获取权限点树形结构中已经选中的权限id
      // 调用给角色分配权限的请求接口
      await assignPermission({id: this.currentRoleId, permIds: this.$refs.tree.getCheckedKeys()})
      this.$message.success('分配权限成功')
      // 关闭弹层
      this.permissionVisible = false
    }
  },
  created() {
    this.getRoleList()
  }
}
</script>

<style scoped>
  .operate {
    margin-bottom: 10px;
  }
  .app-container {
    padding: 20px;
  }
  .el-table {
    font-size: 14px;
  }
</style>